﻿using d1Common;
using d1Common.WebController;
using d1Project.Modules.Common.do4A.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization.Json;
using System.Threading.Tasks;
using System.Web;

namespace d1Project.Modules.Common.do4A.Domain
{
    public class ThirdPartAuthenticationMgr
    {
        private static ThirdPartAuthenticationMgr singleInstance = new ThirdPartAuthenticationMgr();
        public static ThirdPartAuthenticationMgr Instance
        {
            get
            {
                return singleInstance;
            }
        }

        private ThirdPartUser getThirdPartUserFromDb(do4ADbContext db, string _appType, string _openId, string _nickName, string _image, string _sex)
        {
            DateTime _dtNow = DateTime.Now;
            var _thirdPartUser = db.ThirdPartUser2s.Where(x => (x.OpenId == _openId)).FirstOrDefault();
            if (_thirdPartUser != null)
            {
                _thirdPartUser.LastLoginTime = _dtNow;
                db.Entry(_thirdPartUser).State = System.Data.Entity.EntityState.Modified;
                db.SaveChanges();
                return _thirdPartUser;
            }
            User2 _user2 = new User2();
            _user2.Id = doServices.Instance.DoCore.getGUID();
            _user2.Code = "";
            _user2.Name = _nickName;
            _user2.Icon = _image;
            _user2.Sex = _sex;
            _user2.MobilePhone = "";
            _user2.IsAvailable = "1";
            _user2.CreateTime = _dtNow;
            _user2.UpdateTime = _dtNow;
            db.User2s.Add(_user2);

            _thirdPartUser = new Models.ThirdPartUser();
            _thirdPartUser.Id = doServices.Instance.DoCore.getGUID();
            _thirdPartUser.UserId = _user2.Id;
            _thirdPartUser.AppType = _appType;
            _thirdPartUser.OpenId = _openId;
            _thirdPartUser.NickName = _nickName;
            _thirdPartUser.Image = _image;
            _thirdPartUser.Sex = _sex;
            _thirdPartUser.CreateTime = _dtNow;
            _thirdPartUser.LastLoginTime = _dtNow;
            db.ThirdPartUser2s.Add(_thirdPartUser);

            db.SaveChanges();

            return _thirdPartUser;
        }

        //参考文档：https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=&lang=zh_CN
        private class Model_WeiXin
        {
            public string access_token { get; set; }
            public int expires_in { get; set; }
            public string refresh_token { get; set; }
            public string openid { get; set; }
            public string scope { get; set; }
            public string unionid { get; set; }
        }
        private class Model2_WeiXin
        {
            public string openid { get; set; }
            public string nickname { get; set; }
            public int sex { get; set; }
            public string province { get; set; }
            public string city { get; set; }
            public string country { get; set; }
            public string headimgurl { get; set; }
            public string unionid { get; set; }
        }
        private async Task<ThirdPartUser> getAppUserInfo_WeiXin(do4ADbContext db, string _code)
        {
            HttpClient client = new HttpClient();
            string _appid = doServices.Instance.DoConfig.readConfigStringValue(do4AModule.ModuleIdDefine, "ThirdPartAuth", "WeiXin_appid", "");
            if (_appid == null || _appid.Length <= 0) throw new Exception("未定义配置项WeiXin_appid");
            string _appsecret = doServices.Instance.DoConfig.readConfigStringValue(do4AModule.ModuleIdDefine, "ThirdPartAuth", "WeiXin_secret", "");
            if (_appsecret == null || _appsecret.Length <= 0) throw new Exception("未定义配置项WeiXin_secret");
            HttpResponseMessage _resultMessage = await client.GetAsync("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" +
                _appid + "&secret=" + _appsecret + "&code=" + _code + "&grant_type=authorization_code");
            string _resultString = await _resultMessage.Content.ReadAsStringAsync();
            Model_WeiXin resultObject = JsonConvert.DeserializeObject<Model_WeiXin>(_resultString);
            if (resultObject.openid == null || resultObject.openid.Length <= 0) throw new UserException("微信用户认证失败");

            HttpResponseMessage _resultMessage2 = await client.GetAsync("https://api.weixin.qq.com/sns/userinfo?access_token=" +
                resultObject.access_token + "&openid=" + resultObject.openid + "&lang=zh-CN");
            string _resultString2 = await _resultMessage2.Content.ReadAsStringAsync();
            Model2_WeiXin resultObject2 = JsonConvert.DeserializeObject<Model2_WeiXin>(_resultString2);
            if (resultObject2.openid == null || resultObject2.openid.Length <= 0) throw new UserException("微信用户认证失败");

            return this.getThirdPartUserFromDb(db, "WeiXin", resultObject2.openid, resultObject2.nickname, resultObject2.headimgurl, resultObject2.sex == 1 ? "1" : "0");
        }


        //参考文档：http://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8sdk%E5%AE%9E%E7%8E%B0qq%E7%9A%84%E7%99%BB%E5%BD%95%E5%92%8C%E6%B3%A8%E9%94%80_android_sdk
        //参考文档2：http://wiki.connect.qq.com/%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7openid_oauth2-0
        private class Model_QQ
        {
            public int ret { get; set; }
            public string msg { get; set; }
            public string nickname { get; set; }
            public string figureurl { get; set; }
            public string figureurl_1 { get; set; }
            public string figureurl_2 { get; set; }
            public string figureurl_qq_1 { get; set; }
            public string figureurl_qq_2 { get; set; }
            public string gender { get; set; }
            public string is_yellow_vip { get; set; }
            public string vip { get; set; }
            public string yellow_vip_level { get; set; }
            public string level { get; set; }
            public string is_yellow_year_vip { get; set; }
        }

        private async Task<ThirdPartUser> getAppUserInfo_QQ(do4ADbContext db, string _accessToken, string _openId)
        {
            HttpClient client = new HttpClient();
            string _appid = doServices.Instance.DoConfig.readConfigStringValue(do4AModule.ModuleIdDefine, "ThirdPartAuth", "QQ_appid", "");
            if (_appid == null || _appid.Length <= 0) throw new Exception("未定义配置项QQ_appid");
            HttpResponseMessage _resultMessage = await client.GetAsync("https://graph.qq.com/user/get_user_info?access_token=" +
                _accessToken + "&oauth_consumer_key=" + _appid + "&openid=" + _openId);
            var _resultStream = _resultMessage.Content.ReadAsStreamAsync();
            var serializer = new DataContractJsonSerializer(typeof(Model_QQ));
            Model_QQ resultObject = serializer.ReadObject(_resultStream.Result) as Model_QQ;
            if (resultObject.ret != 0) throw new UserException(resultObject.msg);
            return this.getThirdPartUserFromDb(db, "QQ", _openId, resultObject.nickname, resultObject.figureurl_qq_1, resultObject.gender == "女" ? "0" : "1");
        }

        //http://open.weibo.com/wiki/Oauth2/get_token_info
        private class Model_SinaWeiBo
        {
            public int subscribe { get; set; }
            public string uid { get; set; }
            public string nicname { get; set; }
            public string sex { get; set; }
            public string city { get; set; }
            public string country { get; set; }
            public string province { get; set; }
            public string language { get; set; }
            public string headimgurl { get; set; }
            public string headimgurl_large { get; set; }
            public string headimgurl_hd { get; set; }
            public int subscribe_time { get; set; }
            public string follow { get; set; }
        }

        //参考：http://open.weibo.com/wiki/%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF
        private async Task<ThirdPartUser> getAppUserInfo_SinaWeiBo(do4ADbContext db, string _access_token, string _uid)
        {
            HttpClient client = new HttpClient();
            string _appid = doServices.Instance.DoConfig.readConfigStringValue(do4AModule.ModuleIdDefine, "ThirdPartAuth", "SinaWeiBo_appid", "");
            if (_appid == null || _appid.Length <= 0) throw new Exception("未定义配置项SinaWeiBo_appid");
            string _appsecret = doServices.Instance.DoConfig.readConfigStringValue(do4AModule.ModuleIdDefine, "ThirdPartAuth", "SinaWeiBo_secret", "");
            if (_appsecret == null || _appsecret.Length <= 0) throw new Exception("未定义配置项SinaWeiBo_secret");
            List<KeyValuePair<String, String>> paramList = new List<KeyValuePair<String, String>>();
            paramList.Add(new KeyValuePair<string, string>("access_token", _access_token));
            HttpResponseMessage _resultMessage = await client.GetAsync("https://api.weibo.com/2/eps/user/info.json?access_token=" +
                _access_token + "&uid=" + _uid);
            var _resultStream = _resultMessage.Content.ReadAsStreamAsync();
            var serializer = new DataContractJsonSerializer(typeof(Model_SinaWeiBo));
            Model_SinaWeiBo resultObject = serializer.ReadObject(_resultStream.Result) as Model_SinaWeiBo;
            if (resultObject.uid == null || resultObject.uid.Length <= 0 || resultObject.uid != _uid) throw new Exception("新浪微博获取用户信息失败");
            return this.getThirdPartUserFromDb(db, "SinaWeiBo", resultObject.uid, resultObject.nicname, resultObject.headimgurl, resultObject.sex == "2" ? "0" : "1");
        }

        public async Task<string> getAccessToken(do4ADbContext db, string _appType, string _appCode, string _appOpenId, string _appAccessToken)
        {
            if (_appType == "WeiXin")
            {
                ThirdPartUser _thirdPartUser = await ThirdPartAuthenticationMgr.Instance.getAppUserInfo_WeiXin(db, _appCode);
                return AuthenticationMgr.Instance.CheckThirdPartToken2(_appType, _thirdPartUser.UserId);
            }
            if (_appType == "QQ")
            {
                ThirdPartUser _thirdPartUser = await ThirdPartAuthenticationMgr.Instance.getAppUserInfo_QQ(db, _appAccessToken, _appOpenId);
                return AuthenticationMgr.Instance.CheckThirdPartToken2(_appType, _thirdPartUser.UserId);
            }
            if (_appType == "SinaWeiBo")
            {
                ThirdPartUser _thirdPartUser = await ThirdPartAuthenticationMgr.Instance.getAppUserInfo_SinaWeiBo(db, _appAccessToken, _appOpenId);
                return AuthenticationMgr.Instance.CheckThirdPartToken2(_appType, _thirdPartUser.UserId);
            }
            throw new Exception("AppType无效");
        }
    }
}